/**
 * The Interface class will get the user input, generates and send a message object to MessagePasser of the parent.
 */
import java.util.*;
import java.sql.Timestamp;
import common.*;

public class Interface extends Thread{
	private Process parent;
	private boolean running;
	
	private Scanner key_in;
	
	public Interface( Process _parent ){
		parent = _parent;
		key_in = new Scanner( System.in );
		turnoff();	// prevent the screen from getting swamped by prompts
	}
	
	/**
	 * Thread core: This does receive string input from the user, parse the input, and trigger the requested task or send a message 
	 */
	public void run(){
		while( running ){
			System.out.print( parent.myID + "$ " );
			String input = key_in.nextLine();
			
			StringTokenizer input_tokens = new StringTokenizer( input );
						
			// input handling
			if( input_tokens.hasMoreTokens() ){		// check: 1st token
				String command = null;
				
				boolean msg_created = false;
				int msg_type = Def.NOT_ASSIGNED;
				int msg_rid = Def.NOT_ASSIGNED;
				String msg_location = null;
				String msg_file = null;
				
				// decide the type of command
				command = input_tokens.nextToken();		// copy: 1st token
				command = command.trim();
				if( command.toLowerCase().equals( "help" ) ){
					System.out.println( "\n-shell: [ HELP :: Message Rules ]" );
					System.out.println( "$ ls  --  show the list of local files" );
					System.out.println( "$ ls (id)  --  show the list of remote files on (id)" );
					System.out.println( "$ say (id) (msg)  --  send a message" );
					System.out.println( "$ read (id) (location) (file)  --  read a file" );
					System.out.println( "$ write (id) (location) (file)  --  write a file" );
					System.out.println( "$ terminate  --  terminate the process" );
					System.out.println( "$ kill (id)  --  kill a process" );
					System.out.println();
					 
				}else if( command.toLowerCase().equals( "ls" ) ){
					if( input_tokens.hasMoreTokens() ){		// check: 2nd token
						// remote ls
						msg_type = Def.LS;
					}else{
						// local ls
						parent.print_filelist();
						continue;
					}
				}else if( command.toLowerCase().equals( "gls" ) ){
					// global ls
					parent.print_filelist();
					continue;
				}else if( command.toLowerCase().equals( "say" ) ){
					msg_type = Def.MSG;
					
				}else if( command.toLowerCase().equals( "read" ) ){
					msg_type = Def.REQUEST_READ;
					
				}else if( command.toLowerCase().equals( "write" ) ){
					msg_type = Def.REQUEST_WRITE;
					
				}else if( command.toLowerCase().equals( "terminate" ) ){
					System.out.println( "Process " + parent.myID + " is terminating" );
					//parent.shutdown();
					
				}else if( command.toLowerCase().equals( "kill" ) ){
					msg_type = Def.KILL;
					
				}else{
					System.out.println( "-shell: " + command + ": command not found" );
				}
				
				// decide the receiver's ID
				if( msg_type != Def.NOT_ASSIGNED ){
					if( input_tokens.hasMoreTokens() ){		// check: 2nd token
						String temp = input_tokens.nextToken();		// copy: 2nd token
						
						if( Utils.isNumber( temp ) ){
							msg_rid = Integer.parseInt( temp );
							
							// need to check the routing table, if the receiver exists
						}
					}
					
					if( msg_rid == Def.NOT_ASSIGNED ){	// if it still doesn't have the receiver's id,
						System.out.println( "-shell: " + command + " needs (receiver_ID) as a parameter (type HELP for more instruction)" );
					}
				}//end-of-if( msg_type != Def.NOT_ASSIGNED )
				
				// more parameters - location, file
				if( msg_type == Def.REQUEST_READ || msg_type == Def.REQUEST_WRITE ){
					if( input_tokens.hasMoreTokens() ){			// check: 3rd token
						msg_location = input_tokens.nextToken();		// copy: 3rd token
					
						if( input_tokens.hasMoreTokens() ){			// check: 4th token
							msg_file = input_tokens.nextToken();		// copy: 4th token
							msg_created = true;	// REQUEST_READ and REQUEST_WRITE must have 4 paramesters
						}else
							System.out.println( "-shell: " + command + " needs (filename) as a parameter (type HELP for more instruction)" );
					}else
						System.out.println( "-shell: " + command + " needs (location) as a parameter (type HELP for more instruction)" );
					
					
				}else if( msg_type == Def.MSG ){
					if( input_tokens.hasMoreTokens() ){			// check: 3rd token
						msg_location = "";		// copy: 3rd token
						msg_file = input_tokens.nextToken();
						msg_created = true;	// MSG must have 3 paramesters
					}else
						System.out.println( "-shell: " + command + " needs (location) as a parameter (type HELP for more instruction)" );
					
				}else if( msg_type != Def.NOT_ASSIGNED && msg_rid != Def.NOT_ASSIGNED ){
					msg_created = true;
				}//end-of-if( msg_type == Def.REQUEST_READ || msg_type == Def.REQUEST_WRITE )
				//
				// -- PARSING IS DONE -- //
				
				
				
				// -- create a MSG and send it -- //
				if( msg_created ){
					long msg_time_ms = System.currentTimeMillis();
					
					if( msg_type == Def.NOT_ASSIGNED )
						Utils.print_log( "ERROR: critical error (check your code @438uva) -- Interface.java" );
					
					// create a msg + send
					if( msg_type == Def.REQUEST_READ || msg_type == Def.REQUEST_WRITE ){// for broadcasting
						// create a msg
						Message msg = new Message( msg_type, msg_rid, parent.myID, msg_time_ms, msg_location + msg_file, null );
						
						// create a local request record and store
						if( Conf.ME_SCHEME == Def.ME_TOKENLESS ){	// for TOKENLESS (Ricart-Agrawala)
							
							// -- CREATE a LOCAL RECORD for EACH REQUEST --
							// * note: the constructor of 'CriticalSectionRecord' will generate a record
							//     for this CS request according to the information in 'msg.'
							CriticalSectionRecord cs_record = new CriticalSectionRecord( msg );		
							parent.cs_my_requests.add( cs_record );
							
							// **broadcast** the msg (1-to-n)
							msg.set_receiver_id( -1 );
							parent.get_postman().send( msg );

							
						}else{	// for TOKEN-based (Raymond)
							
							// actions for a REQUEST
							// create a msg
							// Message msg = new Message( msg_type, msg_rid, parent.myID, msg_time_ms, msg_location + msg_file, null );
							// parent.get_postman().send( msg );
							
						}
						
						
					}else{	// messages other than REQEUEST_READ || REQUEST_WRITE
						// create a msg
						Message msg = new Message( msg_type, msg_rid, parent.myID, msg_time_ms, msg_location + msg_file, null );
						// send the msg (1-to-1)
						parent.get_postman().send( msg );
						
					}
					
					System.out.println( "-shell: your message is sent" );
					
				}//end-of-if( msg_created )
			}//end-of-if( input_tokens.hasMoreTokens() )
		}//end-of-while
	}//end-of-run()
	
	// displays the text message from the other nodes
	public void show_message( Message msg ){
		System.out.println( "-shell: You've got a message from (" + msg.get_sender_id() + "): \""
							+ msg.get_content() + "\" [" + new Timestamp( msg.get_timestamp() ) + "]" );
	}
	
	// These turn on/off the user interface of a node (required for simulation with multiple nodes, to make all nodes shut up but one talk). 
	public void turnoff(){ running = false; }
	public void turnon(){ running = true; start(); }
}//end-of-class
